Building with HyperBEAM 
Master modern AO development patterns with HyperBEAM's high-performance features. This guide covers exposing process state via HTTP, dynamic reads, and practical patterns for building decentralized applications.
Exposing Process State via HTTP: The Foundation 
HyperBEAM enables direct HTTP access to your process state, replacing the old dry-run pattern with instant data access. For the basics, see the Welcome Guide - this section covers comprehensive patterns for real applications.
The Patch Device 
The [email protected] device makes process state readable via HTTP GET requests:
-- Expose data via HTTP
Send({
  device = '[email protected]',
  counter = 42,
  status = "active",
  users = { alice = 100, bob = 200 }
})Access immediately at:
  https://forward.computer/<process-id>[email protected]/compute/counter
  https://forward.computer/<process-id>[email protected]/compute/status
  https://forward.computer/<process-id>[email protected]/compute/usersInitial State Sync Pattern 
Make critical data available immediately on process creation:
-- Initialize state
Balances = { alice = 1000, bob = 500 }
TotalSupply = 1500
-- Sync once on process load
InitialSync = InitialSync or 'INCOMPLETE'
if InitialSync == 'INCOMPLETE' then
  Send({
    device = '[email protected]',
    balances = Balances,
    totalsupply = TotalSupply
  })
  InitialSync = 'COMPLETE'
endDynamic Reads: Compute on Demand 
Dynamic reads enable on-the-fly computations without modifying process state.
Transformation Functions 
Create Lua scripts that process cached state:
-- circulating-supply.lua
function calculate(base, req)
  local totalSupply = 0
  local holderCount = 0
  if base.balances then
    for address, balance in pairs(base.balances) do
      local numBalance = tonumber(balance) or 0
      totalSupply = totalSupply + numBalance
      holderCount = holderCount + 1
    end
  end
  return {
    CirculatingSupply = tostring(math.floor(totalSupply)),
    HolderCount = tostring(holderCount),
    LastCalculated = os.time()
  }
endPublishing and Using Functions 
- Upload your script to Arweave:
npm i -g @permaweb/arx
arx upload circulating-supply.lua -w wallet.json -t arweave --content-type application/lua- Call via HyperBEAM URL:
GET /<process-id>[email protected]/now/[email protected]&module={SCRIPT_TX_ID}/calculate/[email protected]- Use in JavaScript:
async function getCirculatingSupply(processId, scriptTxId) {
  const url = `https://forward.computer/${processId}[email protected]/now/[email protected]&module=${scriptTxId}/calculate/[email protected]`;
  const response = await fetch(url);
  const data = await response.json();
  return {
    supply: data.circulatingsupply,
    holders: data.holdercount,
  };
}Common Patterns 
Token Process Pattern 
-- Token state
Balances = Balances or {}
TotalSupply = TotalSupply or 0
Name = "MyToken"
Ticker = "MTK"
-- Initial state sync
InitialSync = InitialSync or 'INCOMPLETE'
if InitialSync == 'INCOMPLETE' then
  Send({
    device = '[email protected]',
    cache = {
      balances = Balances,
      totalsupply = tostring(TotalSupply),
      name = Name,
      ticker = Ticker
    }
  })
  InitialSync = 'COMPLETE'
end
-- Transfer handler
Handlers.add(
  "Transfer",
  Handlers.utils.hasMatchingTag("Action", "Transfer"),
  function(msg)
    local target = msg.Tags.Target
    local amount = tonumber(msg.Tags.Amount)
    if not target or not amount or amount <= 0 then
      return msg.reply({ Error = "Invalid transfer parameters" })
    end
    local senderBalance = tonumber(Balances[msg.From]) or 0
    if senderBalance < amount then
      return msg.reply({ Error = "Insufficient balance" })
    end
    -- Update balances
    Balances[msg.From] = tostring(senderBalance - amount)
    Balances[target] = tostring((tonumber(Balances[target]) or 0) + amount)
    -- Expose updated state
    Send({
      device = '[email protected]',
      balances = Balances,
      totalsupply = tostring(TotalSupply)
    })
    return msg.reply({
      Status = "Success",
      From = msg.From,
      To = target,
      Amount = tostring(amount)
    })
  end
)Chat Process Pattern 
-- Chat state
Messages = Messages or {}
Users = Users or {}
-- Add message handler
Handlers.add(
  "AddMessage",
  Handlers.utils.hasMatchingTag("Action", "AddMessage"),
  function(msg)
    local content = msg.Data
    local user = msg.From
    if not content or content == "" then
      return msg.reply({ Error = "Message cannot be empty" })
    end
    -- Add message
    local messageId = tostring(#Messages + 1)
    Messages[messageId] = {
      id = messageId,
      user = user,
      content = content,
      timestamp = os.time()
    }
    -- Track user
    Users[user] = (Users[user] or 0) + 1
    -- Expose updated state
    Send({
      device = '[email protected]',
      messages = Messages,
      users = Users,
      messageCount = tostring(#Messages),
      userCount = tostring(table.getn(Users))
    })
    return msg.reply({
      Status = "Message added",
      MessageId = messageId
    })
  end
)
-- Get messages handler
Handlers.add(
  "GetMessages",
  Handlers.utils.hasMatchingTag("Action", "GetMessages"),
  function(msg)
    local limit = tonumber(msg.Tags.Limit) or 50
    local result = {}
    -- Get latest messages
    local count = 0
    for i = #Messages, 1, -1 do
      if count >= limit then break end
      table.insert(result, Messages[i])
      count = count + 1
    end
    return msg.reply({
      Data = json.encode(result),
      Count = tostring(count)
    })
  end
)Integration with External Systems 
Web Frontend Integration 
class AOProcessClient {
  constructor(processId, hyperbeamUrl = "https://forward.computer") {
    this.processId = processId;
    this.hyperbeamUrl = hyperbeamUrl;
  }
  // Read state via HTTP
  async getState(key) {
    const url = `${this.hyperbeamUrl}/${this.processId}[email protected]/compute/${key}`;
    const response = await fetch(url);
    return await response.text();
  }
  // Send message to process
  async sendMessage(action, tags = {}, data = "") {
    const message = {
      target: this.processId,
      tags: [
        { name: "Action", value: action },
        ...Object.entries(tags).map(([k, v]) => ({ name: k, value: v })),
      ],
      data,
    };
    // Use aoconnect to send message
    const result = await message({
      process: this.processId,
      signer: this.signer,
      ...message,
    });
    return result;
  }
  // Get dynamic computation result
  async getDynamicResult(scriptTxId, functionName) {
    const url = `${this.hyperbeamUrl}/${this.processId}[email protected]/now/[email protected]&module=${scriptTxId}/${functionName}/[email protected]`;
    const response = await fetch(url);
    return await response.json();
  }
}
// Usage example
const client = new AOProcessClient("your-process-id");
// Read counter value
const counter = await client.getState("counter");
// Send increment message
await client.sendMessage("Increment");
// Get computed circulating supply
const supply = await client.getDynamicResult("script-tx-id", "calculate");API Gateway Pattern 
Create an API gateway that aggregates data from multiple processes:
class AOGateway {
  constructor() {
    this.processes = new Map();
  }
  registerProcess(name, processId) {
    this.processes.set(name, processId);
  }
  async getAggregatedState() {
    const results = {};
    for (const [name, processId] of this.processes) {
      try {
        const response = await fetch(
          `https://forward.computer/${processId}[email protected]/compute/status`,
        );
        results[name] = await response.text();
      } catch (error) {
        results[name] = "Error: " + error.message;
      }
    }
    return results;
  }
}Best Practices 
State Management 
- Use descriptive keys in cache tables (avoid state,info,test)
- Always use lowercase for cache keys (HTTP paths are case-insensitive)
- Batch updates when possible for efficiency
- Initialize state sync for critical data
Performance 
- Patch frequently updated data for real-time access
- Use dynamic reads for complex computations
- Cache expensive calculations in transformation functions
- Minimize payload sizes for better performance
Security 
- Validate inputs in all handlers
- Check permissions before state modifications
- Use rate limiting for expensive operations
- Never expose sensitive data via HTTP state access
Next Steps 
Continue to Concepts & Migration to understand the underlying architecture, or explore the Tutorials for hands-on projects.
Need Help? 
- Join the Discord community
- Check the HyperBEAM documentation
- Browse the Guides for specific patterns